//################################
// 版权所有：中国农业银行软件开发中心
// 系统名称：移动办公应用-手机版
// 文件名称：index.js
// 创建时间：2016年10月29日
// 创建人员：Panda
// 功能说明：switch index
//################################

'use strict';

import React, {PropTypes, Component} from 'react';
import {
    View,
    StyleSheet,
    TouchableHighlight,
    Animated,
    PanResponder,
} from 'react-native';

class PandaSwitch extends Component {
    static defaultProps = {
        activeBackgroundColor: '#37B9D080',
        inactiveBackgroundColor: 'rgba(0,0,0,.2)',
        switchHeight: 20,
        switchWidth: 40,
        buttonRadius: 15,
        switchAnimationTime: 200,
        onActivate: () => null,
        onDeactivate: () => null,
        onChangeState: () => null,
        activeButtonPressedColor: '#37B9D0',
        inactiveButtonPressedColor: '#37B9D0',
        buttonShadow: {
            shadowColor: '#000',
            shadowOpacity: 0.5,
            shadowRadius: 1,
            shadowOffset: { height: 1, width: 0 },
        },
        enableSlide: true,
        active: false,
        inactiveButtonColor: '#2196F3',
        activeButtonColor: '#37B9D0',
        buttonContent: null,
        styles: {},
    };

    static propTypes = {
        activeBackgroundColor: PropTypes.string,
        inactiveBackgroundColor: PropTypes.string,
        switchHeight: PropTypes.number,
        switchWidth: PropTypes.number,
        buttonRadius: PropTypes.number,
        switchAnimationTime: PropTypes.number,
        onActivate: PropTypes.func,
        onDeactivate: PropTypes.func,
        onChangeState: PropTypes.func,
        activeButtonPressedColor: PropTypes.string,
        inactiveButtonPressedColor: PropTypes.string,
        buttonShadow: PropTypes.object,
        enableSlide: PropTypes.bool,
        active: PropTypes.bool,
        inactiveButtonColor: PropTypes.string,
        activeButtonColor: PropTypes.string,
        buttonContent: PropTypes.element,
        styles: PropTypes.object,
    };

    constructor(props) {
        super(props);
        
        this.padding = 2;
        this.start = {};

        let w = this.props.switchWidth - Math.min(this.props.switchHeight, this.props.buttonRadius * 2);
        
        this.activate = this.activate.bind(this);
        this.deactivate = this.deactivate.bind(this);

        this.state = {
            state: this.props.active,
            pressed: true,
            position: new Animated.Value(this.props.active ? w : 0),
            width: w,
        };
    }

    toggle() {
        if (this.state.state) {
            this.deactivate();
        }
        else {
            this.activate();
        }
    }

    activate() {
        Animated.timing(
            this.state.position,
            {
                toValue: this.state.width,
                duration: this.props.switchAnimationTime,
            }
        ).start();
        this.changeState(true);
    }

    deactivate() {
        Animated.timing(
            this.state.position,
            {
                toValue: 0,
                duration: this.props.switchAnimationTime,
            }
        ).start();
        this.changeState(false);
    }

    changeState(state) {
        let callHandlers = this.start.state != state;
        setTimeout(() => {
            this.setState({
                state: state,
            });
            // if (callHandlers) {
                this.callback();
            // }
        }, this.props.switchAnimationTime / 2);
    }

    callback() {
        let state = this.state.state;
        if (state) {
            this.props.onActivate();
        }
        else {
            this.props.onDeactivate();
        }
        this.props.onChangeState(state);
    }

    componentWillMount () {
        this._panResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
            onPanResponderGrant: (evt, gestureState) => {
                this.setState({pressed: true});
                this.start.x0 = gestureState.x0;
                this.start.pos = this.state.position._value;
                this.start.moved = false;
                this.start.state = this.state.state;
                this.start.stateChanged = false;
            },
            onPanResponderMove: (evt, gestureState) => {
                if (!this.props.enableSlide) return;

                this.start.moved = true;
                if (this.start.pos == 0) {
                    if (gestureState.dx <= this.state.width && gestureState.dx >= 0) {
                        this.state.position.setValue(gestureState.dx);
                    }
                    if (gestureState.dx > this.state.width) {
                        this.state.position.setValue(this.state.width);
                    }
                    if (gestureState.dx < 0) {
                        this.state.position.setValue(0);
                    }
                }
                if (this.start.pos == this.state.width) {
                    if (gestureState.dx >= -this.state.width && gestureState.dx <= 0) {
                        this.state.position.setValue(this.state.width + gestureState.dx);
                    }
                    if (gestureState.dx > 0) {
                        this.state.position.setValue(this.state.width);
                    }
                    if (gestureState.dx < -this.state.width) {
                        this.state.position.setValue(0);
                    }
                }
                var currentPos = this.state.position._value;
                this.onSwipe(currentPos, this.start.pos,
                    () => {
                        if (!this.start.state) this.start.stateChanged = true;
                        this.setState({state: true})
                    },
                    ()=>{
                        if (this.start.state) this.start.stateChanged = true;
                        this.setState({state: false})
                    }
                );
            },
            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onPanResponderRelease: (evt, gestureState) => {
                this.setState({pressed: false});
                var currentPos = this.state.position._value;
                if (!this.start.moved || (Math.abs(currentPos-this.start.pos)<5 && !this.start.stateChanged)) {
                    this.toggle();
                    return;
                }
                this.onSwipe(currentPos, this.start.pos, this.activate, this.deactivate);
            },
            onPanResponderTerminate: (evt, gestureState) => {
                var currentPos = this.state.position._value;
                this.setState({pressed: false});
                this.onSwipe(currentPos, this.start.pos, this.activate, this.deactivate);
            },
            onShouldBlockNativeResponder: (evt, gestureState) => true,
        });
    }

    onSwipe(currentPosition, startingPosition, onChange, onTerminate) {
        if (currentPosition-startingPosition >= 0) {
            if (currentPosition-startingPosition > this.state.width/2 || startingPosition == this.state.width) {
                onChange();
            } else {
                onTerminate();
            }
        }
        else {
            if (currentPosition-startingPosition < -this.state.width/2) {
                onTerminate();
            } else {
                onChange();
            }
        }
    }
    
    render() {
        let doublePadding = this.padding * 2 - 2;
        let halfPadding = doublePadding / 2;

        return (
            <View style={[styles.container, {padding: this.padding}]}>
                <View style={{
                    backgroundColor: this.state.state ? this.props.activeBackgroundColor : this.props.inactiveBackgroundColor,
                    height: this.props.switchHeight,
                    width: this.props.switchWidth,
                    borderRadius: this.props.switchHeight / 2,
                }}/>
                <TouchableHighlight
                    underlayColor={'transparent'}
                    activeOpacity={1}
                    onPress={() => {this.toggle()}}
                    style={{
                        height: Math.max(this.props.buttonRadius * 2 + doublePadding, this.props.switchHeight + doublePadding),
                        width: this.props.switchWidth + doublePadding,
                        position: 'absolute',
                        top: 1,
                        left: 1,
                    }}>
                    <Animated.View style={[{
                        backgroundColor: this.state.state ? (this.state.pressed ? this.props.activeButtonPressedColor : this.props.activeButtonColor) : (this.state.pressed ? this.props.inactiveButtonPressedColor : this.props.inactiveButtonPressedColor),
                        height: this.props.buttonRadius * 2,
                        width: this.props.buttonRadius * 2,
                        borderRadius: this.props.buttonRadius,
                        alignItems: 'center',
                        justifyContent: 'center',
                        flexDirection: 'row',
                        position: 'absolute',
                        top: halfPadding + this.props.switchHeight / 2 - this.props.buttonRadius,
                        left: this.props.switchHeight / 2 > this.props.buttonRadius ? halfPadding : halfPadding + this.props.switchHeight / 2 - this.props.buttonRadius,
                        transform: [{ translateX: this.state.position }],
                    }, this.props.buttonShadow]}
                    {...this._panResponder.panHandlers}>
                        {this.props.buttonContent}
                    </Animated.View>
                </TouchableHighlight>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        position: 'relative',
    },
});

export default PandaSwitch;